﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Net;
using System.Runtime.InteropServices;
using System.Runtime.Remoting.Messaging;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.Drawing.Drawing2D;
 

namespace TCPDemo
{
    internal class SocketServerComm
    {

         public Action<string,bool>  MsgEvent;

        private TcpModule tcpModule;

        //数据处理委托
        public delegate void DataAccessDelegate(object sender, CommonArgs e);
        //数据处理事件
        public DataAccessDelegate OnDataAccess;

        public SocketServerComm(TcpModule myTcpModule )
        {
               tcpModule = myTcpModule;
                handle = GCHandle.Alloc(this, GCHandleType.Normal);
        }
        public   void Dispose()
        {
            StopConnection();
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }

        private GCHandle handle;
        private bool disposed = false;
        private DateTime dataDealTime = DateTime.Now;
        protected virtual void Dispose(bool disposing)
        {
            if (!disposed)
            {
                if (disposing)
                {
                    // 释放托管资源
                }

                // 释放非托管资源...
                if (handle.IsAllocated)
                {
                    handle.Free(); // 释放GCHandle，让GC可以回收该对象
                }

                disposed = true;
            }
        }

        ~SocketServerComm()
        {
            Dispose(false);
        }


        public   bool IsConnected()
        {
            return IsStart;
        }

        public CancellationTokenSource tokenSource;


        public   void StartConnection()
        {
            //服务器已经其中侦听，则返回
            if (IsStart) return;

            tokenSource = new CancellationTokenSource();

            Task.Factory.StartNew(() => { DoMinitor(); });

            //服务器启动侦听
            try
            {
                IPEndPoint localep = new IPEndPoint(IPAddress.Parse(tcpModule.LocalIP),tcpModule.LocalPort);
                //IPEndPoint localep = new IPEndPoint(IPAddress.Parse("192.168.130.72"), 8077);
                listener = new TcpListener(localep);
                listener.Start(100);
            }
            catch (Exception ex)
            {
                 
                this.ShowMsg(string.Format("端口{0}错误，请修改后重试:{1}", this.tcpModule.LocalPort, ex.Message),false);
                return;
            }
            IsStart = true;
            this.ShowMsg(string.Format(string.Format("服务器已经启动侦听！端点为：{0}。", listener.LocalEndpoint.ToString())));
         
            //接受连接请求的异步调用
            //AsyncCallback callback = new AsyncCallback(AcceptCallback);
            listener.BeginAcceptSocket(new AsyncCallback(AcceptCallback), listener);

        }

        public   void StopConnection()
        {
            try
            {
                tokenSource.Cancel();
                if (!IsStart) return;
                listener.Stop();
                IsStart = false;


                lock (friends)
                {
                    MyFriend[] mfs = (MyFriend[])friends.ToArray(typeof(MyFriend));
                    foreach (MyFriend myFriend in mfs)
                    {
                        myFriend.socket.Shutdown(SocketShutdown.Both);
                        // myFriend.socket.Close(1000);
                    }
                }
            }
            catch (Exception ex)
            {
                this.ShowMsg(string.Format("端口{0}停止监听失败:{1}", this.tcpModule.LocalPort, ex.Message), false);
                
            }

        }

        public   void Write(string info)
        {


            MyFriend[] mfs = (MyFriend[])friends.ToArray(typeof(MyFriend));
            if (mfs.Count() > 0)
            {
                MyFriend myFriend = mfs.LastOrDefault();
                if (!myFriend.socket.Poll(10, SelectMode.SelectRead))
                {
                    //byte[] buffer = Encoding.UTF8.GetBytes(mes);
                    myFriend.socket.Send(Encoding.UTF8.GetBytes(info));
                    this.ShowMsg(string.Format("TCP发送数据:{0}", info), true);
                }
                else
                {

                    RemoveMethod(myFriend);
                }
            }
        }


        ArrayList friends = new ArrayList();  //保存与客户相关的信息的列表
        TcpListener listener;                      //负责侦听的套接字
        bool IsStart = false;                      //指示是否已经启动了侦听


        private void AcceptCallback(IAsyncResult ar)
        {
            try
            {

                //完成异步接受连接请求的异步调用
                //将连接信息添加到列表和下拉列表框中
                Socket handle = listener.EndAcceptSocket(ar);
                MyFriend frd = new MyFriend(handle);
                AddMethod(frd);
                //AsyncCallback callback;
                //继续调用异步方法接收连接请求
                if (IsStart)
                {
                    //callback = new AsyncCallback(AcceptCallback);
                    listener.BeginAcceptSocket(new AsyncCallback(AcceptCallback), listener);
                }
                //开始在连接上进行异步的数据接收
                frd.ClearBuffer();
                // callback = new AsyncCallback(ReceiveCallback);
                frd.socket.BeginReceive(frd.Rcvbuffer, 0, frd.Rcvbuffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), frd);
            }
            catch (Exception ex)
            {
                //listBox1.Invoke(AppendString,exception
                //在调用EndAcceptSocket方法时可能引发异常
                //——套接字Listener被关闭，则设置为未启动侦听状态
                IsStart = false;
            }
        }

        private void AddMethod(MyFriend frd)
        {
            lock (friends)
            {
                MyFriend[] mfs = (MyFriend[])friends.ToArray(typeof(MyFriend));
                foreach (var myFriend in mfs)
                {
                    if (myFriend.socket != null && !myFriend.socket.Poll(10, SelectMode.SelectRead))
                    {

                    }
                    else
                    {
                        RemoveMethod(myFriend);
                    }
                }
                this.ShowMsg(string.Format($"客户端[{frd.socket.LocalEndPoint}]连接TCP服务端[{this.tcpModule.LocalIP}：{this.tcpModule.LocalPort}]成功"));
                friends.Add(frd);
            }

        }

        private void RemoveMethod(MyFriend frd)
        {

            lock (friends)
            {
                friends.Remove(frd);

                this.ShowMsg(string.Format($"客户端[{frd.socket.LocalEndPoint}]与TCP服务端[{this.tcpModule.LocalIP}：{this.tcpModule.LocalPort}]断开连接"), false);
                
            }
            frd.Dispose();
        }


        private void ReceiveCallback(IAsyncResult ar)
        {

            if (!IsStart) return;
            MyFriend frd = (MyFriend)ar.AsyncState;
            try
            {
                int i = frd.socket.EndReceive(ar);

                if (i == 0)
                {
                    return;
                }
                else
                {
                    string data = Encoding.UTF8.GetString(frd.Rcvbuffer, 0, i);
                    InitialRecived();
                    IAsyncResult iar = OnDataAccess.BeginInvoke(this, new CommonArgs(data), new AsyncCallback(callBackAuto), null);
                    frd.ClearBuffer();
                    frd.socket.BeginReceive(frd.Rcvbuffer, 0, frd.Rcvbuffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), frd);
                }
            }
            catch //(Exception ex)
            {
                // Info.Write(string.Format("{0}服务端端数据采集失败", clientName), ex);
            }
        }


        private void callBackAuto(IAsyncResult ar)
        {
            ((DataAccessDelegate)((AsyncResult)ar).AsyncDelegate).EndInvoke(ar);
        }

        private void InitialRecived()
        {
            //if (OnInitialReceived != null)
            //    OnInitialReceived(this, null);
        }



        private void DoMinitor()
        {
            while (!tokenSource.IsCancellationRequested)
            {
                Thread.Sleep(1000);
                if (IsStart)
                {
                    try
                    {
                        MyFriend[] mfs = (MyFriend[])friends.ToArray(typeof(MyFriend));
                        foreach (var myFriend in mfs)
                        {
                            if (myFriend.socket != null && !myFriend.socket.Poll(10, SelectMode.SelectRead))
                            {

                            }
                            else
                            {
                                Thread.Sleep(200);
                                if (myFriend.socket != null && !myFriend.socket.Poll(10, SelectMode.SelectRead))
                                {

                                }
                                else
                                {
                                    RemoveMethod(myFriend);
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        this.ShowMsg(ex.Message, false);
                    }
                }
            }
        }


        public void ShowMsg(string msg, bool res = true)
        {
            if (MsgEvent!=null)
            {
                MsgEvent(msg, res);

            }
            
        }

        public class TcpModule
        { 
          public string LocalIP { get; set; }
          public int LocalPort { get; set; }   
         
        }


        /// <summary>
        /// 通用参数
        /// </summary>
        public class CommonArgs : EventArgs
        {
            public string Param;
            public string[] Values;
            public Object Obj;


            public CommonArgs()
            {
            }


            public CommonArgs(string param)
            {
                this.Param = param;
            }


            public CommonArgs(Object obj)
            {
                this.Obj = obj;
            }


            public CommonArgs(string param, string[] values)
            {
                this.Param = param;
                this.Values = values;
            }

            public CommonArgs(string param, Object obj)
            {
                this.Param = param;
                this.Obj = obj;
            }

            public CommonArgs(string param, string[] values, Object obj)
            {
                this.Param = param;
                this.Values = values;
                this.Obj = obj;
            }
        }

    }

}

